function Interpreter() {
    this.vars = {};
    this.functions = {};
}
Interpreter.prototype.has_declared = function (k) {
    return Object.keys(this.vars).includes(k);
}
Interpreter.prototype.input = function (expression) {
    if ((expression = expression.replace(/\s/g, '')) === '') return '';
    if (/[a-z]/i.test(expression)) {
        if (expression.includes('=')) {
            var k = expression.split('=')[0];
            var v = this.input(expression.split('=')[1]);
            if (this.has_declared(k)) throw 'Error:variable has been declared!';
            return (this.vars[k] = v);
        } else {
            if (/(^[a-z]$)/.test(expression)) {
                if (!this.has_declared(k = RegExp.$1)) throw 'Error:variavle did not exist!';
                return this.vars[k];
            } else {
                expression = expression.replace(/[a-z]/g, (v) => {
                    if (!this.has_declared(v)) throw 'Error:variavle did not exist!'; return this.vars[v];
                });
                return this.input(expression);
            }
        }
    } else {
        expression = expression.replace(/\-\-/g, '+').replace(/(\+\-)|(\-\+)/g, '-');
        while (/\([^()]+\)/.test(expression)) {
            expression = expression.replace(/\(([^()]+)\)/,
                (_, exp) => calc_no_parentheses(exp)
            );
            expression = expression.replace(/\-\-/g, '+').replace(/(\+\-)|(\-\+)/g, '-').replace(/\*\+/g, '*').replace(/\/\+/g, '/');
        }
        return calc_no_parentheses(expression);
    }
};
function calc_no_parentheses(exp) {
    var fn = { '+': (a, b) => a + b, '*': (a, b) => a * b, '/': (a, b) => b / a, '%': (a, b) => b % a };
    //trim head +
    exp = exp.replace(/^\+*/, '').replace(/\s/g, '');
    //all sub as plus negative number
    exp = exp.replace(/(\d+)\-(\d+)/g, (_, a, b) => a + '+-' + b);
    var nums = [];
    var opers = [];
    for (x of exp.match(/(-?\d+(\.\d+)?)|[+*/%]/g)) {
        if (/[*/%]/.test(x)) {
            if (opers.length && opers[opers.length - 1] != '+') nums.push(fn[opers.pop()](nums.pop(), nums.pop()));
            opers.push(x);
        } else if (x === '+') {
            if (opers.length === 0) {
                opers.push(x);
            } else {
                while (opers.length) nums.push(fn[opers.pop()](nums.pop(), nums.pop()));
                opers.push(x);
            }
        } else {
            nums.push(+x);
        }
    }
    while (opers.length) nums.push(fn[opers.pop()](nums.pop(), nums.pop()));
    return nums[0];
}
